##
## Авторские права принадлежат Алифатову Дмитрию Сергеевичу <dmitry@alifatov.ru>
##
## Вы можете использовать данное Программное обеспечение на любом количестве компьютеров.
##
## Не разрешается распространять Программное обеспечение, извлекать его компоненты и создавать производные работы на его основе.
##
import curses
import os
import re
import json
import socket
import time
import subprocess

import pexpect

import npyscreen
import astra

with open("astra_repos.json", "r") as read_file:
    astra_repos = json.load(read_file)

class Form_Update(npyscreen.FormMultiPageAction):
    source_list = ['internet', 'file', 'manual']
    def __init__(self):

        super().__init__(cancel_button=False)
        self.OK_BUTTON_TEXT = "Выход"

    def create(self):
        self.astra_update = astra.Astra_Update()
        self.init()
        self.draw_widgets()

    def init(self):
        self.astra_build = self.astra_update.get_astra_build()
        self.allow_repos = []
        if self.astra_build in ['1.7.0.18']:
            for item in astra_repos:
                if item['ver'] in ['1.7.0.18', '1.7.1.8', ]:
                    self.allow_repos.append(item)
        elif self.astra_build in ['1.7.1.8']:
            for item in astra_repos:
                if item['ver'] in ['1.7.1.8', '1.7.2.5', '1.7.2.11']:
                    self.allow_repos.append(item)
        elif self.astra_build in ['1.7.2.5', '1.7.2.11']:
            for item in astra_repos:
                if item['ver'] in ['1.7.2.5', '1.7.2.11', '1.7.3.7', '1.7.3.10', '1.7.3.13'] and self.astra_update.astra_strict_version(self.astra_build) <= self.astra_update.astra_strict_version(item['ver']):
                    self.allow_repos.append(item)
        elif self.astra_build in ['1.7.3.7', '1.7.3.10', '1.7.3.13', '1.7.4.7']:
            for item in astra_repos:
                if item['ver'] in ['1.7.3.7', '1.7.3.10', '1.7.3.13', '1.7.4.7'] and self.astra_update.astra_strict_version(self.astra_build) <= self.astra_update.astra_strict_version(item['ver']):
                    self.allow_repos.append(item)

        manual_repo = {
            'ver': '',
            'title': 'Самостоятельно выбрать репозиторий',
            'main_iso': [],
            'main_iso_gostsum': [],
            'main': [],
            'base_tgz': [],
            'base_tgz_gostsum': [],
            'base': [],
        }
        self.allow_repos.append(manual_repo)

        self.current_repo = self.allow_repos[0]
        for item in self.allow_repos:
            if self.astra_build == item['ver']:
                self.current_repo = item

        self.selected_repo = self.current_repo
        self.allow_repos_menu_items = []

        for item in self.allow_repos:
            self.allow_repos_menu_items.append(item['title'])
        self.selected_repo_index = 0
        # self.selected_repo_index = len(self.allow_repos_menu_items) - 2

        self.source_index = 0

        if self.selected_repo['ver'] == '':
            self.allow_sources = ['Файлы обновлений', 'Указать репозитори самостоятельно']
            self.source_list = ['file', 'manual']
            self.source = 'file'
        else:
            self.allow_sources = ['Интернет репозиторий', 'Файлы обновлений']
            self.source_list = ['internet', 'file']
            self.source = 'internet'
        self.astra_update_file = None
        self.astra_update_file_checked = False
        self.extended_file = None
        self.extended_file_checked = False



    def draw_widgets(self):

        self.add_widget_intelligent(npyscreen.FixedText, begin_entry_at=4, value=f"Обновление: {self.current_repo['title']}", editable=False)
        message=f"Установлен репозиторий {['main','base','extended'][self.astra_update.get_repo_level()]}. "
        if self.astra_update.upgradable_packages() == 0:
            message += "Все пакеты обновлены."
        else:
            message += f"{self.astra_update.upgradable_packages()} пакетов не обновлены."
        self.add_widget_intelligent(npyscreen.FixedText, begin_entry_at=4,
                                    value=message, editable=False)

        self.nextrely += 1
        self.widget_select_repo = self.add_widget_intelligent(npyscreen.TitleSelectOne, begin_entry_at=22, max_height=5, name='Выберите обновление',
                                    values=self.allow_repos_menu_items, value=self.selected_repo_index, current_cursor=self.selected_repo_index, editable=True, scroll_exit=True)

        self.nextrely += 1
        self.widget_select_source = self.add_widget_intelligent(npyscreen.TitleSelectOne, begin_entry_at=22, max_height=4, name='Выберите источник',
                                    values=self.allow_sources, current_cursor=self.source_index, value=self.source_index, editable=True, scroll_exit=True)

        if self.astra_update.astra_strict_version(self.astra_build) >= self.astra_update.astra_strict_version('1.7.3.7'):
            self.nextrely += 1
            self.widget_select_core_update = self.add_widget_intelligent(npyscreen.Checkbox, begin_entry_at=22,
                                                                             max_height=3,
                                                                             name='Установить последнее доступное ядро?',
                                                                             value=False, editable=True,
                                                                             scroll_exit=True)

        if self.source == 'internet':
            self.repo_type = ['main']
            if self.selected_repo['base']:
                self.repo_type.append('base')
                if self.selected_repo['extended']:
                    self.repo_type.append('extended')
                self.nextrely += 1
                self.widget_select_type_repository = self.add_widget_intelligent(npyscreen.TitleSelectOne,
                                                                                 begin_entry_at=25,
                                                                                 max_height=len(self.repo_type),
                                                                                 name="Выберите репозиторий",
                                                                                 values=self.repo_type,
                                                                                 editable=True,
                                                                                 scroll_exit=True)


            self.nextrely += 1
            self.message = "Добавить интернет репозитории и выполнить обновление?"
            self.InternetUpdateButton = self.add_widget_intelligent(npyscreen.ButtonPress, relx=4, name=self.message,
                                                                    when_pressed_function=self.buttonPress)

        if self.source == 'file':
            if self.selected_repo['main_iso']:
                self.nextrely += 1
                self.message = "Скачать ISO-файл репозитория 'main' с https://download.astralinux.ru?"
                self.astra_updateDownloadButton = self.add_widget_intelligent(npyscreen.ButtonPress, name=self.message,
                                                                        when_pressed_function=self.buttonPress)
                self.add_widget_intelligent(npyscreen.FixedText, relx=6,
                                            value=f"(Скачанный файл {self.selected_repo['main_iso'][0].split('/')[-1]} будет помещен в каталог /mnt)", editable=False)
                self.add_widget_intelligent(npyscreen.FixedText, relx=6,
                                            value=f"(Либо самостоятельно скачайте файл обновления базовго рапозитория (base) и поместите его в каталог /mnt)",
                                            editable=False)
            else:
                self.nextrely += 1
                self.message = "Скачать ISO-файл репозитория 'main' с https://download.astralinux.ru?"
                self.add_widget_intelligent(npyscreen.FixedText, relx=6,
                                            value=f"Самостоятельно скачайте файл обновления осного (main) или базовго (base) рапозитория и поместите его в каталог /mnt",
                                            editable=False)

            self.nextrely += 1
            self.message = "Выберите файл обновления основного (main) или базового (base) репозитория:"
            self.widget_update_repository_file = self.add_widget_intelligent(npyscreen.TitleFilenameCombo, name=self.message,
                                                                    select_dir=False, must_exist=True, confirm_if_exists=False,
                                                                    file_mask='*iso$|.*tgz$|.*tar', value=self.astra_update_file, sort_by_extension=True)
            try:
                if self.astra_update_file[-4:] in ['.tgz','.tar']:
                    self.nextrely += 1
                    self.message = "(опционально) - выберите файл обновления расширенного (extended) репозитория:"
                    self.widget_extended_repository_file = self.add_widget_intelligent(npyscreen.TitleFilenameCombo,
                                                                                     name=self.message,
                                                                                     select_dir=False, must_exist=True,
                                                                                     confirm_if_exists=False,
                                                                                     file_mask='*tar$|.*tgz',
                                                                                     value=self.extended_file,
                                                                                     sort_by_extension=True)
            except:
                pass


            if self.astra_update_file != None:
                self.nextrely += 1
                self.message = "Установить обновление из файла?"
                self.FileUpdateButton = self.add_widget_intelligent(npyscreen.ButtonPress, relx=4, name=self.message,
                                                                        when_pressed_function=self.buttonPress)

        if self.source == 'manual':
            self.widget_sources_list_file = self.add_widget_intelligent(npyscreen.MultiLineEditableBoxed, max_height=(self.max_y - self.nextrely - 4), name='/etc/apt/sources.list:', values=self.etc_apt_sources_list, scroll_exit=True)
            self.message = "Отменить изменения в файле /etc/apt/source_list"
            self.RejectChangesOfSourceListFileButton = self.add_widget_intelligent(npyscreen.ButtonPress, name=self.message,
                                                                    when_pressed_function=self.buttonPress)
            self.message = "Сохранить изменения в файле /etc/apt/source_list и выполнить обновление системы"
            self.SaveSourcesListFileAndUpdateButton = self.add_widget_intelligent(npyscreen.ButtonPress, name=self.message,
                                                                             when_pressed_function=self.buttonPress)
    def adjust_widgets(self, *args, **keywords):
        #выбор репозитория
        if self.selected_repo['title'] != self.allow_repos[self.widget_select_repo.value[0]]['title']:
            self.selected_repo_index = self.widget_select_repo.value[0]
            self.selected_repo = self.allow_repos[self.selected_repo_index]
            self.source_index = 0
            if not self.selected_repo['ver']:
                self.allow_sources = ['Файлы обновлений', 'Указать репозитори самостоятельно']
                self.source_list = ['file', 'manual']
                self.source = 'file'
            else:
                self.allow_sources = ['Интернет репозиторий', 'Файлы обновлений']
                self.source_list = ['internet', 'file']
                self.source = 'internet'
            editw = self.editw
            self.exit_editing()
            self._clear_all_widgets()
            self.draw_widgets()
            self.edit(editw=editw)

        #выбор источника
        if self.widget_select_source.value[0] != self.source_index:
            self.source_index = self.widget_select_source.value[0]
            self.source = self.source_list[self.source_index]
            if self.source == 'manual':
                self.etc_apt_sources_list = []
                file = open('/etc/apt/sources.list', 'r')
                lines = file.readlines()
                for line in lines:
                    self.etc_apt_sources_list.append(line)
                file.close()
            editw = self.editw
            self.exit_editing()
            self._clear_all_widgets()
            self.draw_widgets()
            self.edit(editw=editw)

        if hasattr(self, 'widget_update_repository_file'):
            old_update_file = self.astra_update_file
            if self.widget_update_repository_file != None:
                if os.path.isfile(str(self.widget_update_repository_file.value)):
                    self.astra_update_file = self.widget_update_repository_file.value
                else:
                    self.astra_update_file = None
            else:
                self.astra_update_file = None

            if old_update_file != self.astra_update_file:
                editw = self.editw
                self.exit_editing()
                self._clear_all_widgets()
                self.draw_widgets()
                self.edit(editw=editw)

        if hasattr(self, 'widget_extended_repository_file'):
            olf_extended_file = self.extended_file
            if self.widget_extended_repository_file != None:
                if os.path.isfile(str(self.widget_extended_repository_file.value)):
                    self.extended_file = self.widget_extended_repository_file.value
                else:
                    self.extended_file = None
            else:
                self.extended_file = None

            if olf_extended_file != self.extended_file:
                editw = self.editw
                self.exit_editing()
                self._clear_all_widgets()
                self.draw_widgets()
                self.edit(editw=editw)

    def buttonPress(self):
        arg = ""
        if hasattr(self, 'widget_select_core_update'):
            if self.widget_select_core_update.value:
                arg = "-K"
        #Установка из Интернет репозитория
        if self.InternetUpdateButton.value:
            repo_list = ''
            for item in self.selected_repo['main']:
                repo_list = repo_list + f" {item.split(' ')[0]}"
            if hasattr(self, 'widget_select_type_repository'):
                if self.widget_select_type_repository.value[0] >= 1: #base или extended репозиторий
                    repo_list = ''
                    for item in self.selected_repo['base']:
                        repo_list = repo_list + f" {item.split(' ')[0]}"
                    if self.widget_select_type_repository.value[0] == 2: #extended-репозиторий
                        for item in self.selected_repo['extended']:
                            repo_list = repo_list + f" {item.split(' ')[0]}"

            if self.astra_build in ['1.7.0.18']:
                command = f"astra-update -A -k {repo_list}"
            else:
                command = f"astra-update -A -k -T {arg} {repo_list}"
            astra.frame_system_call(command)
            #if not self.astra_update.upgradable_packages():
            #    if self.astra_build in ['1.7.0.18']:
            #        command = f"astra-update -A -r"
            #    else:
            #        command = f"astra-update -A -r -T {arg}"
            #    frame_system_call(command)
            self.exit_editing()
            self._clear_all_widgets()
            self.init()
            self.draw_widgets()
            self.edit()
        if hasattr(self, 'UpdateDownloadButton'):
            if self.astra_updateDownloadButton.value:
                if self.selected_repo['main_iso']:
                    astra.frame_system_call(f"wget -P /mnt -c '{self.selected_repo['main_iso'][0]}'")
                    self.iso_file='/mnt/' + self.selected_repo['main_iso'][0].split('/')[-1]
                self.exit_editing()
                self._clear_all_widgets()
                self.draw_widgets()
                self.edit()
        #Установка из файла .tgz или .iso
        if hasattr(self, 'FileUpdateButton'):
            if self.FileUpdateButton.value:
                if self.astra_update_file[-4:] in ['.tgz','.tar']:

                    #распаковываем bas-репозиторий и добавляем в sources.list
                    astra.system_call("sudo mkdir /srv/base-repository")
                    str = 'deb file:/srv/base-repository/ 1.7_x86-64 main contrib non-free\n'
                    with open('/etc/apt/sources.list') as f:
                        lines = f.readlines()

                    pattern = re.compile(re.escape(str))
                    with open('/etc/apt/sources.list', 'w') as f:
                        for line in lines:
                            result = pattern.search(line)
                            if result is None:
                                f.write(line)
                        f.write(str)
                    astra.frame_system_call(f"sudo tar zxvf '{self.astra_update_file}' -C /srv/base-repository", pause=None)

                    # распаковываем extended-репозиторий и добавляем в sources.list
                    try:
                        if self.extended_file[-4:] in ['.tgz', '.tar']:
                            astra.system_call("sudo mkdir /srv/extended-repository")
                            str = 'deb file:/srv/extended-repository/ 1.7_x86-64 main contrib non-free\n'
                            with open('/etc/apt/sources.list') as f:
                                lines = f.readlines()

                            pattern = re.compile(re.escape(str))
                            with open('/etc/apt/sources.list', 'w') as f:
                                for line in lines:
                                    result = pattern.search(line)
                                    if result is None:
                                        f.write(line)
                                f.write(str)
                            astra.frame_system_call(f"sudo tar zxvf '{self.extended_file}' -C /srv/extended-repository",
                                              pause=None)
                    except:
                        pass

                    astra.frame_system_call(f"sudo apt update", pause=None)

                    if self.astra_build in ['1.7.0.18']:
                        astra.frame_system_call(f"sudo astra-update -A -r")
                    else:
                        astra.frame_system_call(f"sudo astra-update -A -r -T {arg}")

                elif self.astra_update_file[-4:] == '.iso':
                    astra.frame_system_call(f"sudo astra-update -A {arg} '{self.astra_update_file}'")
                else:
                    self.astra_update_file = None
                self.exit_editing()
                self._clear_all_widgets()
                self.init()
                self.draw_widgets()
                self.edit()

        # Отменить изменения в /etc/apt/source.lists
        if hasattr(self, 'RejectChangesOfSourceListFileButton'):
            if self.RejectChangesOfSourceListFileButton.value:
                self.etc_apt_sources_list = []
                file = open('/etc/apt/sources.list', 'r')
                lines = file.readlines()
                for line in lines:
                    self.etc_apt_sources_list.append(line)
                file.close()
                editw = self.editw
                self.exit_editing()
                self._clear_all_widgets()
                self.draw_widgets()
                self.edit(editw=editw)

        # Сохранить изменения в /etc/apt/source.lists
        if hasattr(self, 'SaveSourcesListFileAndUpdateButton'):
            if self.SaveSourcesListFileAndUpdateButton.value:
                self.etc_apt_sources_list = self.widget_sources_list_file.values
                file = open('/etc/apt/sources.list', 'w')
                for line in self.etc_apt_sources_list:
                    if line[-1] != '\n':
                        line += '\n'
                    file.write(line)
                file.close()
                astra.frame_system_call(f"sudo apt update", pause=None)
                if self.astra_build in ['1.7.0.18']:
                    astra.frame_system_call(f"sudo astra-update -A -r")
                else:
                    astra.frame_system_call(f"sudo astra-update -A -r -T {arg}")
                editw = self.editw
                self.exit_editing()
                self._clear_all_widgets()
                self.init()
                self.draw_widgets()
                self.edit(editw=editw)

    def on_ok(self):
        pass
